//
//  MCResponseTool.m
//  iMooc
//
//  Created by CoderXSLee on 13/6/3.
//  Copyright © 2013年 李雪松. All rights reserved.
//

#import "MCResponseTool.h"
#import "MCNetworking.h"
#import "MCAnalyzedResult.h"
#import <CommonCrypto/CommonDigest.h>

#if __has_include(<MJExtension/MJExtension.h>)
#import <MJExtension/MJExtension.h>
#elif __has_include("MJExtension.h")
#import "MJExtension.h"
#endif


#if __has_include(<AFNetworking/AFURLResponseSerialization.h>)
#import <AFNetworking/AFURLResponseSerialization.h>
#elif __has_include("AFURLResponseSerialization.h")
#import "AFURLResponseSerialization.h"
#endif



#ifdef DEBUG
//#define MCLog(...) NSLog(__VA_ARGS__)
#define MCLog(fmt,...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__,__LINE__,##__VA_ARGS__);
#else
#define MCLog(...)
#endif

@implementation MCResponseTool

// 统一的业务解析方法
+ (void)analyzeDataWithResult:(MCCommonResult *)result response:(id)response modelClass:(Class)modelClass analyzedBlock:(AnalyzedBlock)analyzedBlock {
    MCAnalyzedResult *analyzeResult = nil;
    id data = nil;
    // 请求成功的处理
    if (result.resultCode == MC_RESULT_SUCCESS) {
        // Json -> Dictionary
        data = [MCResponseTool requestDispose:response];
        // 处理业务层的结果码
        analyzeResult = [MCAnalyzedResult resultWithResponse:data request:result.request];
        @try {
            if (data != nil && data != [NSNull null] && [data isKindOfClass:[NSDictionary class]]) {
                // 如果请求的数据 有 data 这个 key
                NSString *dataKey = [MCNetworking sharedInstance].responseObjectKeys[@"responseDataKey"];
                if ([[data allKeys] containsObject:dataKey]) {
                    data = [data objectForKey:dataKey];
                }
                // 如果 modelClass != nil 则进行 字典 -> 模型 解析
                if (data != nil && data != [NSNull null] && modelClass != nil) {
                    if ([data isKindOfClass:[NSDictionary class]]) {
                        data = [modelClass mj_objectWithKeyValues:data];
                    }else if ([data isKindOfClass:[NSArray class]] && modelClass != nil) {
                        data = [modelClass mj_objectArrayWithKeyValuesArray:data];
                    }
                }
            }
        } @catch (NSException *exception) {
            // 解析失败
            MCLog(@"MCResponseTool data 解析失败: %@", [exception description]);
        } @finally { }
    }
    
    // 请求失败
    if (result.resultCode == MC_RESULT_FAILURE) {
        // 判断 response 是否为 NSError 是否为网络异常等
        NSString *resultDesc;
        MCResultCode resultCode;
        if (response != nil && response != [NSNull null] && [response isKindOfClass:[NSError class]]) {
            NSError *error = response;
            if (error.code == NSURLErrorUnknown) {
                resultDesc = @"无效的URL地址";
                resultCode = MCErrorTip;
            }else if (error.code == NSURLErrorCancelled) {
                resultDesc = @"已取消";
                resultCode = MCErrorTip;
            }else if (error.code == NSURLErrorTimedOut) {
                resultDesc = @"请求超时,请检查网络或服务器";
                resultCode = MCErrorTip;
            }else if (error.code == NSURLErrorUnsupportedURL) {
                resultDesc = @"不支持的URL地址";
                resultCode = MCErrorTip;
            }else if (error.code == NSURLErrorCannotFindHost) {
                resultDesc = @"未找到服务器";
                resultCode = MCErrorTip;
            }else if (error.code == NSURLErrorCannotConnectToHost) {
                resultDesc = @"无法连接服务器";
                resultCode = MCErrorTip;
            }else if (error.code == NSURLErrorNetworkConnectionLost) {
                resultDesc = @"网络连接丢失";
                resultCode = MCNetworkAbnormal;
            }else if (error.code == 15791) {
                resultDesc = @"禁止使用代理，请关闭后重试";
                resultCode = MCErrorTip;
            }else if (error.code == NSPropertyListReadCorruptError) {
                // 404 || 503 等不做处理，直接抛出
                NSError *error2 = [error.userInfo objectForKey:@"NSUnderlyingError"];
                NSString *desc = [error2.userInfo objectForKey:@"NSLocalizedDescription"];
                // NSHTTPURLResponse *response = [error2.userInfo objectForKey:AFNetworkingOperationFailingURLResponseErrorKey];
                // resultDesc = [NSString stringWithFormat:@"%ld-服务器错误", response.statusCode];
                resultDesc = desc;
                resultCode = MCErrorTip;
            }else if (error.code == NSURLErrorNotConnectedToInternet) {
                resultDesc = @"似乎已断开与互联网的连接";
                resultCode = MCNetworkAbnormal;
            }else if (error.code == NSURLErrorBadServerResponse) {
                MCCommonResult *commonResult = [MCResponseTool requestBadServerResponseError:response];
                resultCode = MC_RESULT_FAILURE;
                resultDesc = [NSString stringWithFormat:@"%ld - %@", (long)commonResult.resultCode, commonResult.resultDesc];;
            }else {// 其他错误
                NSError *underly = [error.userInfo objectForKey:@"NSUnderlyingError"];
                NSString *description = [underly.userInfo objectForKey:@"NSLocalizedDescription"];
                resultDesc = description;
                resultCode = MCErrorTip;
            }
        }
        // 失败统一处理结果码以及描述
        analyzeResult = [MCAnalyzedResult resultWithCode:resultCode desc:resultDesc request:result.request];
    }    // 成功与失败的回调
    if (analyzedBlock) {
        analyzedBlock(analyzeResult, data);
    }
}


/**
 请求失败的错误结果码信息 http bad request code = 400 时，
 有特殊情况比如说参数错误，服务器返回了400，在此封装了失败的结果data需要解析。该情况比较罕见。
 */
+ (MCCommonResult *)requestBadServerResponseError:(NSError *)error {
    NSData *data = [error.userInfo objectForKey:AFNetworkingOperationFailingURLResponseDataErrorKey];
    NSDictionary *dict = [MCResponseTool requestDispose:data];
    MCCommonResult *result = [MCCommonResult resultWithResponse:dict request:nil];
    return result;
}

#pragma mark Networking Data Dispose Method 网络请求的数据处理
/// 网络结果集处理 JSON -> NSDictionary
+ (NSDictionary *)requestDispose:(id)responseObject {
    // 若为字典，直接返回
    if ([responseObject isKindOfClass:[NSDictionary class]]) {
        return responseObject;
    }
    // 转换成 字符串
    NSString *decodeJson = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
    if (!decodeJson) {
        NSAssert(!decodeJson, @"decodeJson is nil");
        return nil;
    }
    decodeJson = [self deleteSpecialCodeWithStr:decodeJson];
    // 字符串转成流
    NSData *data = [decodeJson dataUsingEncoding:NSUTF8StringEncoding];
    // 转换字典
    NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
    return dictionary;
}

#pragma mark -- 处理json格式的字符串中的换行符、回车符
+ (NSString *)deleteSpecialCodeWithStr:(NSString *)string {
    NSString *str;
    str = [string stringByReplacingOccurrencesOfString:@"\r" withString:@""];
    str = [string stringByReplacingOccurrencesOfString:@"\n" withString:@""];
    str = [string stringByReplacingOccurrencesOfString:@"\n" withString:@""];
    str = [string stringByReplacingOccurrencesOfString:@"\t" withString:@""];
    str = [string stringByReplacingOccurrencesOfString:@" " withString:@""];
    str = [string stringByReplacingOccurrencesOfString:@"(" withString:@""];
    str = [string stringByReplacingOccurrencesOfString:@")" withString:@""];
    return str;
}


// 根据 url 跟 parameter 获取 缓存的 key
+ (NSString *)getCacheKeyWithUrlString:(NSString *)url parameters:(NSDictionary *)parameters {
    // 处理空格
    url = [url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    if (!parameters) {
        return [self md5WithString:url];
    }
    NSMutableArray *paramArray = [NSMutableArray array];
    [parameters enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        // 接收key
        NSString *finalKey = [key stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
        // 防止数据非对象类型造成崩溃，因字典不可存基本数据类型
        if ([obj isKindOfClass:[NSNumber class]]) {
            obj = [obj stringValue];
        }else if ([obj isKindOfClass:[NSArray class]] && [obj count] < 1) {
            obj = @"";
        }
        // 接收值
        NSString *finalValue = [obj stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
        NSString *part =[NSString stringWithFormat:@"%@=%@",finalKey, finalValue];
        [paramArray addObject:part];
    }];
    NSString *parameterString = [paramArray componentsJoinedByString:@"&"];
    parameterString = parameterString ? parameterString : @"";
    NSString *cacheKey = [NSString stringWithFormat:@"%@?%@",url, parameterString];
    return [self md5WithString:cacheKey];
}

+ (NSString *)md5WithString:(NSString *)string {
    const char *original_str = [string UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(original_str, (CC_LONG)strlen(original_str), result);
    NSMutableString *hash = [NSMutableString string];
    for (int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [hash appendFormat:@"%02x", result[i]];
    }
    return [hash lowercaseString];
}


@end
